package org.beetl.support;

import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.beetl.sql.core.ClasspathLoader;
import org.beetl.sql.core.ConnectionSource;
import org.beetl.sql.core.Interceptor;
import org.beetl.sql.core.NameConversion;
import org.beetl.sql.core.SQLLoader;
import org.beetl.sql.core.SQLManager;
import org.beetl.sql.core.StandardNameConversion;
import org.beetl.sql.core.db.DBStyle;
import org.beetl.sql.core.db.H2Style;
import org.beetl.sql.core.db.MySqlStyle;
import org.beetl.sql.core.db.OracleStyle;
import org.beetl.sql.core.db.SqliteStyle;
import org.beetl.sql.ext.DebugInterceptor;

public class SQLManagerBuilder {

 private DBStyle dbStyle;
 private SQLLoader sqlLoader;
 private ConnectionSource cs;
 private NameConversion nc;
 private List<Interceptor> interceptors = new ArrayList<Interceptor>();

 public SQLManagerBuilder dbStyle(DBStyle dbStyle) {
  this.dbStyle = dbStyle;
  return this;
 }

 public SQLManagerBuilder sqlLoader(SQLLoader sqlLoader) {
  this.sqlLoader = sqlLoader;
  return this;
 }

 public SQLManagerBuilder connectionSource(ConnectionSource cs) {
  this.cs = cs;
  return this;
 }

 public SQLManagerBuilder NameConversion(NameConversion nc) {
  this.nc = nc;
  return this;
 }

 public SQLManagerBuilder interceptor(Interceptor... items) {
  if (items != null) {
   for (Interceptor inter : items) {
    interceptors.add(inter);
   }
  }
  return this;
 }

 public SQLManagerBuilder debug() {
  if (LogSupport.isDebugEnabled()) {
   this.interceptors.add(new DebugInterceptor());
  }
  return this;
 }

 public NameConversion onBuildNameConversion() {
  return new StandardNameConversion();
 }

 public DBStyle onResolveDBStyle(DatabaseMetaData dbMeta) throws SQLException {
  String dbProductName = dbMeta.getDatabaseProductName();
  LogSupport.info("onResolveDBStyle: productName={}", dbProductName);
  if (CommonSupport.containsIgnoreCase(dbProductName, "mysql")) {
   return new MySqlStyle();
  }
  if (CommonSupport.containsIgnoreCase(dbProductName, "oracle")) {
   return new OracleStyle();
  }
  if (CommonSupport.containsIgnoreCase(dbProductName, "sqlite")) {
   return new SqliteStyle();
  }
  if (CommonSupport.containsIgnoreCase(dbProductName, "h2")) {
   return new H2Style();
  }
  LogSupport.error("can't resolve dbStyle for productName={}", dbProductName);
  return null;
 }

 public SQLLoader onBuildSQLLoader() {
  return new ClasspathLoader("/sql");
 }

 public SQLManager build() {
  // public SQLManager(DBStyle dbStyle, SQLLoader sqlLoader,
  // ConnectionSource ds, NameConversion nc, Interceptor[] inters) {
  // beetl = new Beetl(sqlLoader);
  // this.dbStyle = dbStyle;
  // this.sqlLoader = sqlLoader;
  // this.ds = ds;
  // this.nc = nc;
  // this.inters = inters;
  // this.dbStyle.setNameConversion(this.nc);
  // this.dbStyle.setMetadataManager(initMetadataManager());
  // this.dbStyle.init(beetl);
  // }
  if (this.nc == null) {
   this.nc = this.onBuildNameConversion();
  }
  if (this.sqlLoader == null) {
   this.sqlLoader = this.onBuildSQLLoader();
  }
  if (this.dbStyle == null) {
   // resolve dbStyle from metaData
   if (this.cs != null) {
    try {
     this.dbStyle = onResolveDBStyle(this.cs.getMaster().getMetaData());
    } catch (SQLException e) {
     throw new RuntimeException(e);
    }
   }
  }
  CommonSupport.throwIfNull(this.dbStyle, "DbStyle required.");
  Interceptor[] inters = new Interceptor[this.interceptors.size()];
  this.interceptors.toArray(inters);
  return new SQLManager(dbStyle, sqlLoader, cs, nc, inters);
 }
}
